﻿/*
Copyright (c) 2009 Vratislav Cermak (vratacermak@gmail.com)
 
This file is part of TeachMe Project. See http://code.google.com/p/teach-me for more information.
 
TeachMe is an open source project. Using of TeachMe is free of charge.
It is distributed under GNU General Public License version 3 (GPLv3).
GPLv3 can be found at http://www.gnu.org/licenses/gpl.html.
 
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System;
using TeachMe.Application.Configuration;

namespace TeachMe.Application
{
    public class HotkeysManager
    {
        readonly Dictionary<HotkeyType, ushort> _registered = new Dictionary<HotkeyType, ushort>();
        private readonly UserSettings _userSettings;

        public HotkeysManager(UserSettings userSettings)
        {
            _userSettings = userSettings;

            Initialize();
        }

        public HotkeyType GetHotkeyType(ushort id)
        {
            foreach (KeyValuePair<HotkeyType, ushort> pair in _registered)
            {
                if (pair.Value == id)
                {
                    return pair.Key;
                }
            }

            throw new ArgumentException();
        }

        public void UnregisterAll()
        {
            foreach (KeyValuePair<HotkeyType, ushort> pair in _registered)
            {
                Unregister(pair.Key);
            }

            _registered.Clear();
        }

        public void RegisterAll()
        {
            foreach (Hotkey hotkey in _userSettings.Hotkeys)
            {
                Keys modifiers, key;

                if (hotkey.Get(out modifiers, out key))
                {
                    Register(hotkey.Type, modifiers, key);
                }
            }
        }

        private void Initialize()
        {
            foreach (Hotkey hotkey in _userSettings.Hotkeys)
            {
                Keys modifiers, key;

                if (hotkey.Get(out modifiers, out key))
                {
                    Register(hotkey.Type, modifiers, key);
                }
            }
        }

        private void Register(HotkeyType hotkeyType, Keys modifiers, Keys key)
        {
            Logging.Debug(GetType(), "Registering hotkey '{0}' to '{1}' + '{2}'.", hotkeyType, modifiers, key);

            if (_registered.ContainsKey(hotkeyType))
            {
                if (!Unregister(hotkeyType))
                {
                    return;
                }

                _registered.Remove(hotkeyType);
            }

            ushort id = Win32.NativeMethods.GlobalAddAtom(Guid.NewGuid().ToString());

            if (id == 0)
            {
                Logging.Error(GetType(), "Global atom could not be created.");
                
                return;
            }

            int fsModifiers = 0;

            if ((modifiers & Keys.Control) == Keys.Control)
            {
                fsModifiers |= Win32.Constants.MOD_CONTROL;
            }
            if ((modifiers & Keys.Alt) == Keys.Alt)
            {
                fsModifiers |= Win32.Constants.MOD_ALT;
            }
            if ((modifiers & Keys.Shift) == Keys.Shift)
            {
                fsModifiers |= Win32.Constants.MOD_SHIFT;
            }
            if ((modifiers & Keys.LWin) == Keys.LWin)
            {
                fsModifiers |= Win32.Constants.MOD_WIN;
            }

            if (!Win32.NativeMethods.RegisterHotKey(IntPtr.Zero, id, (uint) fsModifiers, (uint) key))
            {
                Logging.Error(GetType(), "Hotkey could not be registered.");

                Win32.NativeMethods.GlobalDeleteAtom(id);

                return;
            }

            _registered.Add(hotkeyType, id);
        }

        private bool Unregister(HotkeyType hotkeyType)
        {
            Logging.Debug(GetType(), "Unregistering hotkey '{0}'.", hotkeyType);

            if (!Win32.NativeMethods.UnregisterHotKey(IntPtr.Zero, _registered[hotkeyType]))
            {
                Logging.Error(GetType(), "Hotkey could not be unregistered.");

                return false;
            }

            Win32.NativeMethods.GlobalDeleteAtom(_registered[hotkeyType]);

            return true;
        }

        public bool HasHotkey(HotkeyType type)
        {
            return _userSettings.Hotkeys.Any(hotkey => hotkey.Type == type);
        }

        public bool GetHotkey(HotkeyType type, out Keys modifiers, out Keys key)
        {
            modifiers = Keys.None;
            key = Keys.None;

            foreach (Hotkey hotkey in _userSettings.Hotkeys)
            {
                if (hotkey.Type == type)
                {
                    return hotkey.Get(out modifiers, out key);
                }
            }

            return false;
        }

        public void SetHotkey(HotkeyType type, Keys modifiers, Keys key)
        {
            foreach (Hotkey hotkey in _userSettings.Hotkeys)
            {
                if (hotkey.Type == type)
                {
                    hotkey.Set(modifiers, key);

                    return;
                }
            }

            Hotkey newHotkey = new Hotkey();
            newHotkey.Type = type;
            newHotkey.Set(modifiers, key);
            
            _userSettings.Hotkeys.Add(newHotkey);
        }

        public void RemoveHotkey(HotkeyType type)
        {
            foreach (Hotkey hotkey in _userSettings.Hotkeys)
            {
                if (hotkey.Type == type)
                {
                    _userSettings.Hotkeys.Remove(hotkey);

                    break;
                }
            }   
        }
    }
}
